package com.rtc.agoracall

import android.Manifest
import android.annotation.SuppressLint
import android.content.Intent
import android.content.pm.PackageManager
import android.media.AudioDeviceInfo
import android.media.AudioManager
import android.os.Build
import android.os.Bundle
import android.util.Log
import android.view.View
import android.widget.AdapterView
import android.widget.ArrayAdapter
import android.widget.Toast
import androidx.activity.ComponentActivity
import androidx.lifecycle.ViewModelProvider
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import com.rtc.agoracall.databinding.SampleActivityMainBinding
import com.rtc.call.core.CallCore
import com.rtc.call.core.MediaPlayerManager
import com.rtc.call.core.data.ConfigResponse
import com.rtc.call.core.ConfigManager
import org.json.JSONObject
import java.util.logging.Logger

class MainActivity : ComponentActivity() {

    val TAG = "MainActivity"
    companion object {
        private const val PERMISSION_REQUEST_CODE = 1001
        
        // All permissions that need to be requested
        private val PERMISSIONS = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
            arrayOf(
                Manifest.permission.RECORD_AUDIO,
                Manifest.permission.CAMERA,
                Manifest.permission.READ_EXTERNAL_STORAGE,
                Manifest.permission.WRITE_EXTERNAL_STORAGE,
                Manifest.permission.BLUETOOTH_CONNECT
            )
        } else {
            arrayOf(
                Manifest.permission.RECORD_AUDIO,
                Manifest.permission.CAMERA,
                Manifest.permission.READ_EXTERNAL_STORAGE,
                Manifest.permission.WRITE_EXTERNAL_STORAGE
            )
        }
    }
    
    private lateinit var binding: SampleActivityMainBinding
    private lateinit var viewModel: MainViewModel
    private var callCore: CallCore? = null
    private var playerManager: MediaPlayerManager? = null
    private lateinit var audioManager: AudioManager
    private var inputDevices = mutableListOf<AudioDeviceInfo>()
    private var outputDevices = mutableListOf<AudioDeviceInfo>()
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        
        // Initialize view binding
        binding = SampleActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        // Initialize audio manager
        audioManager = getSystemService(AUDIO_SERVICE) as AudioManager

        playerManager = MediaPlayerManager(context = this)
        playerManager?.createMediaPlayer()

        // Initialize ViewModel
        viewModel = MainViewModel(this)
        
        // Set up button click listeners
        setupClickListeners()
        
        // Observe view model changes
        observeViewModel()
        
        // Request permissions before initializing CallCore
        initCallCore()
        if (!hasPermissions()) {
            Log.d(TAG,"hasPermissions: false")
            requestPermissions()
        } else {
            Log.d(TAG,"hasPermissions: ture")
        }
        binding.etDeviceId.setText(callCore?.getDeviceId())

        setupSaveButton()
        setupAudioDeviceSelection()
    }
    
    override fun onResume() {
        super.onResume()
        
        // For NFC foreground dispatch
        callCore?.getPublicNfcManager()?.enableForegroundDispatch(this)
        
        // Refresh audio devices when the activity resumes
        refreshAudioDevices()
    }
    
    override fun onPause() {
        super.onPause()
        
        // Disable NFC foreground dispatch
        callCore?.getPublicNfcManager()?.disableForegroundDispatch(this)
    }
    
    override fun onNewIntent(intent: Intent) {
        super.onNewIntent(intent)
        
        // Pass the NFC intent to CallCore
        callCore?.handleNfcIntent(intent)
    }
    
    /**
     * Set up button click listeners
     */
    private fun setupClickListeners() {
        // Get config button click listener
        binding.btGetConfig.setOnClickListener {
//            viewModel.getConfig()
            if (callCore == null) {
                initCallCore()
            }
            callCore?.loadTurnOnConfig()
        }
        
        // Deep link button click listener
        binding.btDeep.setOnClickListener {
            // Handle deep link action
            if (callCore == null) {
                initCallCore()
            }
            callCore?.loadNfcOnConfig()
        }
        binding.btOff.setOnClickListener{
            if (callCore == null) {
                initCallCore()
            }
            callCore?.loadNfcOffConfig()
        }
    }
    
    /**
     * Observe ViewModel changes
     */
    private fun observeViewModel() {
        // Observe config loading state
        viewModel.configLoadingState.observe(this) { state ->
            when (state) {
                MainViewModel.ConfigState.LOADING -> {
                    Toast.makeText(this, "Loading configuration...", Toast.LENGTH_SHORT).show()
                }
                MainViewModel.ConfigState.SUCCESS -> {
                    Toast.makeText(this, "Configuration loaded successfully", Toast.LENGTH_SHORT).show()
                }
                MainViewModel.ConfigState.ERROR -> {
                    Toast.makeText(this, "Failed to load configuration", Toast.LENGTH_SHORT).show()
                }
                else -> { /* No action needed */ }
            }
        }
        
        // Observe config data
        viewModel.configData.observe(this) { configData ->
            configData?.let {
                if (callCore == null) {
                    initCallCore()
                }
                // Update the CallCore with the new configuration
                updateCallCoreConfig(it)
            }
        }
    }
    
    /**
     * Update CallCore configuration with the new data
     */
    private fun updateCallCoreConfig(configData: ConfigResponse) {
        callCore?.let { core ->
            // In a real implementation, you would update the configuration here
            Log.d(TAG,"Received config data: $configData")
            core.initialize(configData.agoraAppId,this)

            if (configData.welcomeMp3.isNotEmpty()) {
//                playerManager?.playerUrl(configData.welcomeMp3)
                core.playNetWorkSound(configData.welcomeMp3)
            }
            core.playNetWorkSound(configData.welcomeMp3)
            if (configData.agoraChannel.isNotEmpty()) {
                core.enterRtcChannel(configData.agoraChannel,0,configData.agoraToken)
                core.startDefaultCall()
                core.startNfcDetection()
//                playerManager?.stop()
            }

        }
    }
    
    /**
     * Initialize CallCore after permissions are granted
     */
    private fun initCallCore() {
        callCore = CallCore.getInstance(applicationContext)
        callCore?.initialize()
        Log.d(TAG,"callCore: $callCore")
//        callCore?.initialize("your_agora_app_id", this)
//
//        // Start NFC detection if needed
//        callCore?.startNfcDetection()
    }
    
    /**
     * Check if all required permissions are granted
     */
    private fun hasPermissions(): Boolean {
        return PERMISSIONS.all {
            ContextCompat.checkSelfPermission(this, it) == PackageManager.PERMISSION_GRANTED
        }
    }
    
    /**
     * Request necessary permissions
     */
    private fun requestPermissions() {
        val permissionsToRequest = PERMISSIONS.filter {
            ContextCompat.checkSelfPermission(this, it) != PackageManager.PERMISSION_GRANTED
        }.toTypedArray()
        
        if (permissionsToRequest.isNotEmpty()) {
            ActivityCompat.requestPermissions(
                this,
                permissionsToRequest,
                PERMISSION_REQUEST_CODE
            )
        }
    }
    
    /**
     * Handle permission request results
     */
    @Deprecated("Deprecated in Java")
    override fun onRequestPermissionsResult(
        requestCode: Int,
        permissions: Array<String>,
        grantResults: IntArray
    ) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        
        if (requestCode == PERMISSION_REQUEST_CODE) {
            val allGranted = grantResults.all { it == PackageManager.PERMISSION_GRANTED }
            
            if (allGranted) {
                // All permissions granted, initialize CallCore
                initCallCore()
            } else {
                // Some permissions denied
                Toast.makeText(
                    this,
                    "Some permissions were denied. The app may not function properly.",
                    Toast.LENGTH_LONG
                ).show()

            }
        }
    }
    
    override fun onDestroy() {
        super.onDestroy()
        callCore?.destroy()
        callCore = null
        playerManager?.releasePlayer()
        playerManager = null
    }

    private fun setupSaveButton() {
        binding.btSaveDeviceId.setOnClickListener {
            val deviceId = binding.etDeviceId.text.toString().trim()
            if (deviceId.isNotEmpty()) {
                callCore?.saveDeviceId(deviceId)
                Toast.makeText(this, "Device ID saved successfully", Toast.LENGTH_SHORT).show()
            } else {
                Toast.makeText(this, "Please enter a device ID", Toast.LENGTH_SHORT).show()
            }
        }
    }

    /**
     * Set up audio device selection UI and functionality
     */
    private fun setupAudioDeviceSelection() {
        // Get available audio devices
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            getAvailableAudioDevices()
            
            // Setup input device spinner
            val inputDeviceNames = inputDevices.map { getDeviceName(it) }
            val inputAdapter = ArrayAdapter(this, android.R.layout.simple_spinner_item, inputDeviceNames)
            inputAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
            binding.spinnerInputDevices.adapter = inputAdapter
            
            // Setup output device spinner
            val outputDeviceNames = outputDevices.map { getDeviceName(it) }
            val outputAdapter = ArrayAdapter(this, android.R.layout.simple_spinner_item, outputDeviceNames)
            outputAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
            binding.spinnerOutputDevices.adapter = outputAdapter
            
            // Set button click listener to apply audio device selection
            binding.btApplyAudioSettings.setOnClickListener {
                applyAudioDeviceSelection()
            }
        } else {
            // For older versions, hide the audio device selection UI
            binding.tvAudioDevicesTitle.visibility = View.GONE
            binding.tvInputDeviceLabel.visibility = View.GONE
            binding.spinnerInputDevices.visibility = View.GONE
            binding.tvOutputDeviceLabel.visibility = View.GONE
            binding.spinnerOutputDevices.visibility = View.GONE
            binding.btApplyAudioSettings.visibility = View.GONE
            
            Toast.makeText(this, "音频设备选择功能在您的设备上不可用", Toast.LENGTH_SHORT).show()
        }
    }
    
    /**
     * Get available audio input and output devices (for Android M and above)
     */
    @SuppressLint("WrongConstant")
    private fun getAvailableAudioDevices() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            inputDevices.clear()
            outputDevices.clear()
            
            val devices = audioManager.getDevices(AudioManager.GET_DEVICES_ALL)
            
            for (device in devices) {
                // Add input devices
                if (device.isSource) {
                    inputDevices.add(device)
                }
                
                // Add output devices
                if (device.isSink) {
                    outputDevices.add(device)
                }
            }
            
            Log.d(TAG, "Found ${inputDevices.size} input devices and ${outputDevices.size} output devices")
        }
    }
    
    /**
     * Get a user-friendly name for an audio device
     */
    @SuppressLint("ObsoleteSdkInt")
    private fun getDeviceName(device: AudioDeviceInfo): String {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            val typeName = when (device.type) {
                AudioDeviceInfo.TYPE_BUILTIN_MIC -> "内置麦克风"
                AudioDeviceInfo.TYPE_WIRED_HEADSET -> "3.5mm 有线耳机/麦克风"
                AudioDeviceInfo.TYPE_USB_DEVICE -> "USB-C 设备"
                AudioDeviceInfo.TYPE_USB_HEADSET -> "USB-C 耳机/麦克风"
                AudioDeviceInfo.TYPE_BLUETOOTH_SCO -> "蓝牙耳机/麦克风"
                AudioDeviceInfo.TYPE_BUILTIN_SPEAKER -> "内置扬声器"
                AudioDeviceInfo.TYPE_WIRED_HEADPHONES -> "有线耳机"
                else -> "其他设备"
            }
            
            return "$typeName (${device.productName})"
        }
        return "未知设备"
    }
    
    /**
     * Apply the selected audio devices
     */
    private fun applyAudioDeviceSelection() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            val selectedInputPosition = binding.spinnerInputDevices.selectedItemPosition
            val selectedOutputPosition = binding.spinnerOutputDevices.selectedItemPosition
            
            if (selectedInputPosition != AdapterView.INVALID_POSITION && inputDevices.size > selectedInputPosition) {
                val selectedInputDevice = inputDevices[selectedInputPosition]
                
                // Apply the selected input device using CallCore or Agora SDK
                callCore?.let { core ->
                    // Check if your CallCore has a method to set the audio input device
                    // If not, you may need to implement it using the underlying Agora SDK
                    if (core.setAudioInputDevice(selectedInputDevice.id)) {
                        Toast.makeText(this, "输入设备已切换: ${getDeviceName(selectedInputDevice)}", Toast.LENGTH_SHORT).show()
                    } else {
                        Toast.makeText(this, "无法切换输入设备", Toast.LENGTH_SHORT).show()
                    }
                } ?: run {
                    Toast.makeText(this, "CallCore 未初始化", Toast.LENGTH_SHORT).show()
                }
            }
            
            if (selectedOutputPosition != AdapterView.INVALID_POSITION && outputDevices.size > selectedOutputPosition) {
                val selectedOutputDevice = outputDevices[selectedOutputPosition]
                
                // Apply the selected output device using CallCore or Agora SDK
                callCore?.let { core ->
                    // Check if your CallCore has a method to set the audio output device
                    // If not, you may need to implement it using the underlying Agora SDK
                    if (core.setAudioOutputDevice(selectedOutputDevice.id)) {
                        Toast.makeText(this, "输出设备已切换: ${getDeviceName(selectedOutputDevice)}", Toast.LENGTH_SHORT).show()
                    } else {
                        Toast.makeText(this, "无法切换输出设备", Toast.LENGTH_SHORT).show()
                    }
                } ?: run {
                    Toast.makeText(this, "CallCore 未初始化", Toast.LENGTH_SHORT).show()
                }
            }
        }
    }
    
    /**
     * Refresh the available audio devices list
     */
    private fun refreshAudioDevices() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            getAvailableAudioDevices()
            
            // Update the input device spinner
            val inputDeviceNames = inputDevices.map { getDeviceName(it) }
            val inputAdapter = ArrayAdapter(this, android.R.layout.simple_spinner_item, inputDeviceNames)
            inputAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
            binding.spinnerInputDevices.adapter = inputAdapter
            
            // Update the output device spinner
            val outputDeviceNames = outputDevices.map { getDeviceName(it) }
            val outputAdapter = ArrayAdapter(this, android.R.layout.simple_spinner_item, outputDeviceNames)
            outputAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
            binding.spinnerOutputDevices.adapter = outputAdapter
        }
    }
}


